/**
 * 
 */
package truerefactor.graph;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @author Isaac
 */
public class PackageNode extends CodeNode {

    /**
     * List of Class Nodes contained within this package
     */
    private List<ClassNode> classes;
    /**
     * String representation of the base of this package
     */
    private String base;
    /**
     * Static reference to the default package
     */
    private static final PackageNode DefaultPackage = new PackageNode("", "", "");
    /**
     * List of Packages contained within this package
     */
    private List<PackageNode> subPackages;
    /**
     * Package which contains this package
     */
    private PackageNode superPackage;

    /*
     * (non-Javadoc)
     * @see truerefactor.graph.CodeNode#clone()
     */
    @Override
    protected Object clone() throws CloneNotSupportedException
    {
        return new PackageNode(uid, new String(this.identifier), new String(this.code), new String(this.base));
    }

    /**
     * Creates new instance of PackageNode with the specified identifier and
     * code.
     * 
     * @param identifier
     *            name of the new PackageNode
     * @param code
     *            code of the new PackageNode
     */
    public PackageNode(String identifier, String code)
    {
        this(CodeGraph.nextUID(), identifier, code);
        base = "";
    }

    /**
     * Creates a new instance of PackageNode with the provided simple name and
     * base package name;
     * 
     * @param identifier
     *            package name
     * @param code
     *            code
     * @param base
     *            base package name
     */
    private PackageNode(String identifier, String code, String base)
    {
        this(CodeGraph.nextUID(), identifier, code);
        this.base = base;
    }

    /**
     * Creates a new PackageNode instance
     * 
     * @param uid
     *            unique idetifier
     * @param identifier
     *            package name
     * @param code
     *            code
     * @param base
     *            base package name
     */
    private PackageNode(long uid, String identifier, String code, String base)
    {
        this(uid, identifier, code);
        this.base = base;
    }

    /**
     * Creates a new PackageNode instance
     * 
     * @param uid
     *            unique idetifier
     * @param identifier
     *            package name
     * @param code
     *            code
     */
    private PackageNode(long uid, String identifier, String code)
    {
        super(uid, identifier, code);

        classes = new ArrayList<ClassNode>();
        superPackage = null;
        subPackages = new LinkedList<PackageNode>();
    }

    /*
     * (non-Javadoc)
     * @see truerefactor.graph.CodeNode#add(truerefactor.graph.CodeNode)
     */
    @Override
    public void add(CodeNode child)
    {
        if (child instanceof ClassNode && !classes.contains((ClassNode) child))
        {
            classes.add((ClassNode) child);
        }
    }

    /*
     * (non-Javadoc)
     * @see truerefactor.graph.CodeNode#remove(truerefactor.graph.CodeNode)
     */
    @Override
    public void remove(CodeNode child)
    {
        if (child instanceof ClassNode && classes.contains((ClassNode) child))
        {
            classes.remove((ClassNode) child);
        }
    }

    /*
     * (non-Javadoc)
     * @see truerefactor.graph.CodeNode#getChild(java.lang.String)
     */
    @Override
    public CodeNode getChild(String identfier)
    {
        CodeNode retVal = null;

        for (ClassNode node : classes)
        {
            if (node.getIdentifier().equals(identfier))
            {
                retVal = node;
                break;
            }
        }

        return retVal;
    }

    @Override
    public List<CodeNode> getChildren()
    {
        List<CodeNode> retList = new ArrayList<CodeNode>();
        retList.addAll(classes);

        return retList;
    }

    /**
     * @return the default package instance of PackageNode
     */
    public static PackageNode getDefaultPackage()
    {
        return DefaultPackage;
    }

    /**
     * Sets the base package name to the string provided
     * 
     * @param base
     *            new base package name
     */
    public void setBase(String base)
    {
        this.base = base;
    }

    /**
     * @return base package name for this package
     */
    public String getBase()
    {
        return base;
    }

    /**
     * Adds the provided package as a sub-package of this package
     * 
     * @param subPackage
     *            new sub-package
     */
    public void addSubPackage(PackageNode subPackage)
    {
        if (!subPackages.contains(subPackage))
        {
            subPackage.add(subPackage);
        }
    }

    /**
     * @return returns the super package of this package, or null if there is no
     *         super package
     */
    public PackageNode getSuperPackage()
    {
        return superPackage;
    }

    /**
     * Removes the specified sub-package from this package
     * 
     * @param subPackage
     *            sub-package to remove from this package
     */
    public void removeSubPackage(PackageNode subPackage)
    {
        if (subPackages.contains(subPackage))
        {
            subPackages.remove(subPackage);
        }
    }

    /**
     * @return a list of all direct sub-packages of this package
     */
    public List<PackageNode> getSubPackages()
    {
        return subPackages;
    }

    /**
     * Sets the super package of this package to be the package provided
     * 
     * @param superPackage
     *            new super package of this package
     */
    public void setSuperPackage(PackageNode superPackage)
    {
        this.superPackage = superPackage;
    }

    /**
     * @return all classes within this package
     */
    public List<ClassNode> getClasses()
    {
        return classes;
    }

    /**
     * @return fully qualified name of this package
     */
    public String getFullName()
    {
        return base + "." + identifier;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    public String toString()
    {
        return getFullName();
    }
}
